package com.example.java.newFeature.stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

// Stream API 是 Java 8 引入的一个关键特性，它提供了一种声明性的方法来处理集合数据。
public class StreamDemo {
    // 关于stream流的所有方法使用参考JDK21手册 https://java.cunzaima.cn/jdk21/doc-zh/api/java.base/java/util/stream/Stream.html
    public static void main(String[] args) {
        // 创建一个包含字符串的列表
        List<String> strings = Arrays.asList("apple", "banana", "kiwi", "pear", "grape", "banana", "orange");

        // 综合操作，使用Stream API进行过滤、转换和收集操作
        List<String> result = strings.stream()  // 将列表转换为Stream
                .filter(s -> s.length() > 3) // 过滤流中的元素，只保留满足谓词条件的元素。
                // 通常是用于调试目的，比如打印流中的元素。peek 不会影响流元素本身，也不会改变流的任何操作逻辑。
                .peek(n -> System.out.println("Filtered value: " + n)) // 打印过滤后的值
                .map(String::toUpperCase)  // 将流中的每个元素映射成另一种形式。将字符串转换为大写
                .distinct() // 去除流中的重复元素（根据元素的equals和hashCode方法）。
                .sorted() // 对流中的元素进行自然排序。也可以指定自定义比较器。
                .skip(2) // 跳过流中的前 n 个元素。
                .limit(3) // 限制流中元素的数量，使其不超过给定数量。
                .peek(n -> System.out.println("Result value: " + n)) // 打印映射后的值
                .collect(Collectors.toList());   // 收集结果到一个新的列表，返回的结果是一个可变的集合，允许继续修改集合
                // .toList(); // 收集结果到一个新的列表，使用toList()方法返回的是一个 unmodifiableList 不可修改的集合。不允许再修改。添加、删除元素
                // toList 是 Java 16 及更高版本中引入的一个便利方法，它直接作为Stream接口的一个默认方法存在，无需通过Collectors类来间接调用。
                // toList 方法相当于 .collect(Collectors.toUnmodifiableList())


        List<String> sentences = Arrays.asList(
                "Hello world",
                "Java is fun",
                "Streams make life easier"
        );
        // 使用 flatMap 进行扁平化
        // flatMap 通常用于将流中的元素从嵌套结构（如列表的列表）中提取出来，从而形成一个单一层次的流。
        // 将流中的每个元素转换成流，然后将所有流连接成一个流。
        List<String> words = sentences.stream()
                .flatMap(sentence -> Arrays.stream(sentence.split(" ")))
                .toList();
        // 输出结果
        words.forEach(System.out::println);


        // 打印结果
        System.out.println(result); // 输出: [APPLE, BANANA, GRAPE]
        result.forEach(System.out::println); // 遍历集合
        System.out.println("--------------------------");

        result.add("watermelon");
        result.add("berry");
        result.add("blueberry");
        result.add(1, "banana"); // 在指定位置插入元素
        System.out.println(result);
        result.removeIf(s -> s.startsWith("b"));// 删除所有以b开头的元素
        System.out.println("删除以b开头的元素后：" + result);
        result.addFirst("apple"); // 在第一个位置添加元素
        result.addLast("orange"); // 在最后一个位置添加元素
        System.out.println(result);
        result.set(1, "grapefruit"); // 修改指定位置的元素
        System.out.println(result);
        result.remove("grapefruit"); // 删除指定元素
        System.out.println(result);
        result.clear(); // 清空集合
        System.out.println(result);
        result.addAll(Arrays.asList("apple", "banana", "kiwi", "pear", "grape", "banana", "orange")); // 重新添加元素
        System.out.println("重新添加后：" + result);
        result.replaceAll(s -> s.replace("a", "A")); // 替换所有a为A
        System.out.println("替换后：" + result);
        result.sort(String::compareTo); // 按字母顺序排序
        System.out.println("排序后：" + result);


        // 返回流中元素的个数
        long count = result.stream().skip(1).count();// 计算元素个数
        System.out.println("元素个数：" + count);
        // 返回流中按指定比较器产生的最小元素
        Optional<String> min = result.stream().min(String::compareTo);// 最小值
        min.ifPresent(System.out::println);
        // 返回流中按指定比较器产生的最大元素
        Optional<String> max = result.stream().max(String::compareTo);// 最大值
        max.ifPresent(System.out::println);
        // 聚合操作，将流中的所有元素反复结合起来，得到一个值。
        Optional<String> reduce = result.stream().reduce((s1, s2) -> s1 + s2);// 合并字符串
        reduce.ifPresent(System.out::println);

        // 检查流中是否存在至少一个元素满足给定的谓词条件
        boolean anyMatch = result.stream().anyMatch(s -> s.startsWith("b"));// 是否存在以b开头的元素
        System.out.println("是否存在以b开头的元素：" + anyMatch);
        // 检查流中是否所有元素都满足给定的谓词条件
        boolean allMatch = result.stream().allMatch(s -> s.startsWith("b"));// 是否所有元素都以b开头
        System.out.println("是否所有元素都以b开头：" + allMatch);
        // 检查流中是否没有任何元素满足给定的谓词条件
        boolean noneMatch = result.stream().noneMatch(s -> s.startsWith("b"));// 是否不存在以b开头的元素
        System.out.println("是否不存在以b开头的元素：" + noneMatch);

        // 返回描述此流的第一个元素的 Optional，如果流为空则返回一个空的 Optional。
        result.stream().findFirst().ifPresent(System.out::println);// 第一个元素
        // 返回一个描述流中某个元素的 Optional，如果流为空则返回一个空的 Optional。
        result.stream().findAny().ifPresent(System.out::println);// 任意元素

        // 将集合转换为数组
        String[] array = result.toArray(String[]::new);
        // 将数组转换为集合
        List<String> list = Arrays.stream(array).toList();


        // 使用 peek 方法, 在流处理过程中，可以添加一个中间操作，用于在每个元素被处理之前，打印一个信息。
        Stream.of("one", "two", "three", "four")
                .filter(e -> e.length() > 3)
                .peek(e -> System.out.println("Filtered value: " + e))
                .map(String::toUpperCase)
                .peek(e -> System.out.println("Mapped value: " + e))
                .toList();

        List<String> list1 = new ArrayList<>();
        list1.add("hello");

        List<String> list2 = new ArrayList<>();
        list2.add("world");
        // 合并两个集合
        Stream.concat(list1.stream(), list2.stream())
                .forEach(System.out::println);
    }
}
